use crate::key_manager::algorithm::factory::algorithm_factory::KeyAlgorithm;
use crate::key_manager::error::KeyManagerError;
use crate::register_algorithm;
use anyhow::anyhow;
use anyhow::Result;
use attestation_common::log::{error, info};
use openssl::pkey::PKey;
use openssl::pkey::Private;
use openssl::pkey::Public;
use openssl::rsa::Padding;
use openssl::sign::{RsaPssSaltlen, Signer, Verifier};
/// RSA 算法实现
#[derive(Debug)]
pub struct RsaAlgorithm {
    _bits: u32,
    padding: String,
}

impl KeyAlgorithm for RsaAlgorithm {
    fn derive_public(&self, private_key: &Vec<u8>) -> Result<Vec<u8>, KeyManagerError> {
        info!("RsaAlgorithm: from private key to public key");
        // Trying to load a private key
        let pkey = PKey::private_key_from_pem(&private_key)
            .map_err(|e| KeyManagerError::new(format!("load private key failed: {}", e)))?;
        info!("RsaAlgorithm: load private key success");

        // extracting the public key
        let pub_key = match self.padding.as_str() {
            "pss" => {
                info!("use PSS padding to derive public key");
                let mut signer = openssl::sign::Signer::new_without_digest(&pkey).map_err(|e| {
                    error!("create signer failed: {}", e);
                    KeyManagerError::new(format!("create signer failed: {}", e))
                })?;

                signer.set_rsa_padding(openssl::rsa::Padding::PKCS1_PSS)?;
                signer.set_rsa_mgf1_md(openssl::hash::MessageDigest::sha256())?;
                signer.set_rsa_pss_saltlen(RsaPssSaltlen::MAXIMUM_LENGTH)?;

                pkey.public_key_to_pem().map_err(|e| {
                    error!("public key der encode failed: {}", e);
                    KeyManagerError::new(format!("public key der encode failed: {}", e))
                })?
            }
            _ => {
                info!("use traditional RSA padding to derive public key");
                let rsa = pkey.rsa().map_err(|e| {
                    error!("PKey to RSA failed: {}", e);
                    KeyManagerError::new(format!("PKey to RSA failed: {}", e))
                })?;
                rsa.public_key_to_der().map_err(|e| {
                    error!("public key der encode failed: {}", e);
                    KeyManagerError::new(format!("public key der encode failed: {}", e))
                })?
            }
        };
        info!("RsaAlgorithm: public key der encode success");
        Ok(pub_key)
    }

    fn sign(&self, private_key: &PKey<Private>, data: Vec<u8>) -> Result<Vec<u8>, KeyManagerError> {
        // creating a signer
        let mut signer = Signer::new_without_digest(private_key)?;
        if self.padding == "pss" {
            signer.set_rsa_padding(Padding::PKCS1_PSS)?;
        }

        // signature data
        Ok(signer.sign_oneshot_to_vec(data.clone().as_slice())?)
    }

    fn verify(
        &self,
        public_key: &PKey<Public>,
        data: Vec<u8>,
        signature: Vec<u8>,
    ) -> Result<bool, KeyManagerError> {
        info!("start verify data");
        let mut verifier = Verifier::new_without_digest(public_key)?;
        info!("get public key to verify");
        if self.padding == "pss" {
            verifier.set_rsa_padding(Padding::PKCS1_PSS)?;
            verifier.set_rsa_mgf1_md(openssl::hash::MessageDigest::sha256())?;
            verifier.set_rsa_pss_saltlen(RsaPssSaltlen::MAXIMUM_LENGTH)?;
        }

        Ok(verifier.verify_oneshot(&signature, &data)?)
    }
}

// Auto-registration to global registry
register_algorithm!("rsa", |args: &[&str]| -> Result<Box<dyn KeyAlgorithm>> {
    // Resolve key length
    // The parameter resolution logic must support PSS
    let (bits, padding) = match args {
        [bits_str, "pss"] => (bits_str.parse()?, "pss".to_string()),
        [bits_str] => (bits_str.parse()?, "pkcs1".to_string()),
        _ => return Err(anyhow!("Invalid RSA parameters format")),
    };

    // Validity length
    if ![2048, 3072, 4096].contains(&bits) {
        return Err(anyhow!("SM2 algorithm does not accept parameters"));
    }

    Ok(Box::new(RsaAlgorithm {
        _bits: bits,
        padding,
    }))
});

mod tests {
    #![allow(warnings)]
    use super::*;
    use crate::key_manager::algorithm::factory::algorithm_factory::KeyAlgorithm;
    use crate::key_manager::cache::entity::key_pair::KeyPair;
    use crate::key_manager::util::decode_from_string;
    use once_cell::sync::OnceCell;

    #[test]
    fn test_derive_public() {
        let algorithm = RsaAlgorithm {
            _bits: 2048,
            padding: "pss".to_string(),
        };
        let private_key_str = "\n-----BEGIN PRIVATE KEY-----\nLS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ3dxSnZsOTNjYVhhc1cKQXZBM2hiMkRzTFBvc1RZblhXT1dzUHkySWRiY1dva01nTVR0TWZjbTY5Smc4QVZXTU5idjE2bEFvaDRYaFduQwpLSElFdEthMld0MVhsKy9QV3pYSm16RFI0ZmNCempFYTRKdWNKeElWR1RmV0U0YUY5SmpZZUVhV1FNUnMwT3poClN5Sk54cWtrd0tOMnprQ3R1VWowZkNSNmc1M3ZFeFFpajhtaGYzWktLVW0rSVh5eVFBSFZwM2w3YWVUUWxIV08KSHk0Nk9rTEFHTjVmZWlaTFNYT1k4ais4clpYcUptcjVoWS9rRmV1dUlCZDA4UEdQVW43YnRhNE4zaFlYZ1F4OQpBU3Nna3ZsVTVobVpKN1FSSTdNbVZOSWMxUzMrT3A5TXFXWjdtY0RrUXJIM1FjTjdPSms4STdJR0xUZ2lTTmZICnRTZTVZSnkxQWdNQkFBRUNnZ0VBRjN5REpZTE9BZUpjSVpRSWJjbEpGZDREUFRkNk5LZVUydTd5MmlBTG1jWXIKbkU3dVgzNmFGa0daK2F0UGVsTUo4Rjhpc0dZZFRCRS9xMEdIVHhyWll6c1hYRkxsM2hLSlJ5RnJ6eXVVbEZmZQpiVzFaSXR5SzZlVXRhRGUyVmM3Y0YwTitWdkdMYTlBbS9oam9HYUVFMGM4T3JIZmxYM05Yd0xGVWhEbEZZUWhXCmxualV0Z3R2aVZXa3F3MWppOUtWZjh5MTBaUm5TUHhqQ292K215R3hGUkhXYWFqNHU1Y0VuQkU4MnIzazkrQ1IKNHRXMXRBT0Y1KzNFeC9VZXY5SjlOcmpxWTYwSFBLMHF5bGZudDVGRyttS21YbDBwcFJuZWN4QWtWeVV3dDVQOApLTHNOU21RR3hvamo3RXMwRVBxU1NuVDVXTUR4Ri9XQ3VrUVdIUStTd1FLQmdRRG1PVlJCOGl3bjZDWWFydmJuCmJRbmprN3BRV2l0MTV0VXJrVC9mSUdQT295K2M0R3BMUFdpWjczUkY3TCtNcXNyRXdyc2JqZkZtYjJKbFVmc3oKUmd4a3JMdkczVnplUERwUXFPYUdRUmtNdlp6M3NVaHZKOHJSNUVOYmlVeXM4S1piZlM0RmlSQWp4Rzl4TUoyWgpIb0FCUWVmSHhSRjVEVUk3QUw1NUV4cVdNUUtCZ1FERWIvNGVGNEhxMkhHS1RDR0xvSVpnOFNhY3k3ek9lckg2CmU5UUZwTTJMY3VJcEoyZnQ5WlpWUytNeWJrWURNNTU0TU40ZnlQVmRvQzNoNnpKc3FwdDd5RUZMNjcxejNLeTcKYm51Wno4bHFCNjR1cUNoZXE5WTc3bGZnNWlyZW83b09tL0RZU0JZNmFtOHlLd0VlR3RSSzJicit6TWR0SSs4Twp5SlhGY2ZSWnhRS0JnQ0hmNzVqZ2RFVE84TVJlV0RBSEtEeFhJVVB2Y0pPaGlsNGx1aHN2bmQvcXZQZTlRWWFlCm00U0M2ajNicnZlWXJjc3p4K292QVlVTUFKTmQ4N05BckZRbjRsMUpkdit3SnZoMVVhNFJhQWtxNFN6RTVoNk0KNFZmdTJVWmZ0bXQvNFVwMjZjMmd0RUkvQmhMR2ozblhOZ2g1VlF4YzM4eEsraUxLWWp4WVprSVJBb0dBSzlDMwpJOHNtaFZXRjdjMFJabTJGeTdXK1lSYm9wRDJsMlRNcGxhQ3U0RDNkeUVRcjRGMzVERW1EQWNxcS95ZlNYd2kzCll1dVdIeTROVGVrQ05FN1JvNGlGV0FQYkhDN0tzSHZ5UWRxaEdHOWlJTElOWHlDQkJwa2hMTjdxRFFNRUN5SXAKVkhTdjBKUFEvYVd0K0NNUDJ5bzVsWC9qczZwaU5pL3ppRGprd2VrQ2dZRUFwSVZjTGI2MmtaWWFFaHpHazBRQgpJejk0M3VxekR2YkQvdUxlemdHREFNN09UaEVFRlpkazBOQWwwbnNZV0RQaDJFVXJlSVJvcmx3RkFrVFBMMEw1Cmp3cnprS2RlSDcxemVBSldDWVpVSVhTRVk3Y1J3UEp4S3FKSG44NS9UUVBDdGhlelAwTGxPb0M4L2c2aWlaWmIKRkRNWEhyVjcvRXNRUXdUcjFadEYveWM9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K\n-----END PRIVATE KEY-----\n";
        let private_date = decode_from_string(private_key_str, "pem").unwrap();
        let public_key = algorithm.derive_public(&private_date).unwrap();
        println!("Public key: {:?}", public_key);
    }

    #[test]
    fn test_sign() {
        let algorithm = RsaAlgorithm {
            _bits: 2048,
            padding: "pss".to_string(),
        };
        let private_key_str = "\n-----BEGIN PRIVATE KEY-----\nLS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ3dxSnZsOTNjYVhhc1cKQXZBM2hiMkRzTFBvc1RZblhXT1dzUHkySWRiY1dva01nTVR0TWZjbTY5Smc4QVZXTU5idjE2bEFvaDRYaFduQwpLSElFdEthMld0MVhsKy9QV3pYSm16RFI0ZmNCempFYTRKdWNKeElWR1RmV0U0YUY5SmpZZUVhV1FNUnMwT3poClN5Sk54cWtrd0tOMnprQ3R1VWowZkNSNmc1M3ZFeFFpajhtaGYzWktLVW0rSVh5eVFBSFZwM2w3YWVUUWxIV08KSHk0Nk9rTEFHTjVmZWlaTFNYT1k4ais4clpYcUptcjVoWS9rRmV1dUlCZDA4UEdQVW43YnRhNE4zaFlYZ1F4OQpBU3Nna3ZsVTVobVpKN1FSSTdNbVZOSWMxUzMrT3A5TXFXWjdtY0RrUXJIM1FjTjdPSms4STdJR0xUZ2lTTmZICnRTZTVZSnkxQWdNQkFBRUNnZ0VBRjN5REpZTE9BZUpjSVpRSWJjbEpGZDREUFRkNk5LZVUydTd5MmlBTG1jWXIKbkU3dVgzNmFGa0daK2F0UGVsTUo4Rjhpc0dZZFRCRS9xMEdIVHhyWll6c1hYRkxsM2hLSlJ5RnJ6eXVVbEZmZQpiVzFaSXR5SzZlVXRhRGUyVmM3Y0YwTitWdkdMYTlBbS9oam9HYUVFMGM4T3JIZmxYM05Yd0xGVWhEbEZZUWhXCmxualV0Z3R2aVZXa3F3MWppOUtWZjh5MTBaUm5TUHhqQ292K215R3hGUkhXYWFqNHU1Y0VuQkU4MnIzazkrQ1IKNHRXMXRBT0Y1KzNFeC9VZXY5SjlOcmpxWTYwSFBLMHF5bGZudDVGRyttS21YbDBwcFJuZWN4QWtWeVV3dDVQOApLTHNOU21RR3hvamo3RXMwRVBxU1NuVDVXTUR4Ri9XQ3VrUVdIUStTd1FLQmdRRG1PVlJCOGl3bjZDWWFydmJuCmJRbmprN3BRV2l0MTV0VXJrVC9mSUdQT295K2M0R3BMUFdpWjczUkY3TCtNcXNyRXdyc2JqZkZtYjJKbFVmc3oKUmd4a3JMdkczVnplUERwUXFPYUdRUmtNdlp6M3NVaHZKOHJSNUVOYmlVeXM4S1piZlM0RmlSQWp4Rzl4TUoyWgpIb0FCUWVmSHhSRjVEVUk3QUw1NUV4cVdNUUtCZ1FERWIvNGVGNEhxMkhHS1RDR0xvSVpnOFNhY3k3ek9lckg2CmU5UUZwTTJMY3VJcEoyZnQ5WlpWUytNeWJrWURNNTU0TU40ZnlQVmRvQzNoNnpKc3FwdDd5RUZMNjcxejNLeTcKYm51Wno4bHFCNjR1cUNoZXE5WTc3bGZnNWlyZW83b09tL0RZU0JZNmFtOHlLd0VlR3RSSzJicit6TWR0SSs4Twp5SlhGY2ZSWnhRS0JnQ0hmNzVqZ2RFVE84TVJlV0RBSEtEeFhJVVB2Y0pPaGlsNGx1aHN2bmQvcXZQZTlRWWFlCm00U0M2ajNicnZlWXJjc3p4K292QVlVTUFKTmQ4N05BckZRbjRsMUpkdit3SnZoMVVhNFJhQWtxNFN6RTVoNk0KNFZmdTJVWmZ0bXQvNFVwMjZjMmd0RUkvQmhMR2ozblhOZ2g1VlF4YzM4eEsraUxLWWp4WVprSVJBb0dBSzlDMwpJOHNtaFZXRjdjMFJabTJGeTdXK1lSYm9wRDJsMlRNcGxhQ3U0RDNkeUVRcjRGMzVERW1EQWNxcS95ZlNYd2kzCll1dVdIeTROVGVrQ05FN1JvNGlGV0FQYkhDN0tzSHZ5UWRxaEdHOWlJTElOWHlDQkJwa2hMTjdxRFFNRUN5SXAKVkhTdjBKUFEvYVd0K0NNUDJ5bzVsWC9qczZwaU5pL3ppRGprd2VrQ2dZRUFwSVZjTGI2MmtaWWFFaHpHazBRQgpJejk0M3VxekR2YkQvdUxlemdHREFNN09UaEVFRlpkazBOQWwwbnNZV0RQaDJFVXJlSVJvcmx3RkFrVFBMMEw1Cmp3cnprS2RlSDcxemVBSldDWVpVSVhTRVk3Y1J3UEp4S3FKSG44NS9UUVBDdGhlelAwTGxPb0M4L2c2aWlaWmIKRkRNWEhyVjcvRXNRUXdUcjFadEYveWM9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K\n-----END PRIVATE KEY-----\n";
        let private_date = decode_from_string(private_key_str, "pem").unwrap();
        let data = "Hello, world!".as_bytes().to_vec();
        let pkey = PKey::private_key_from_pem(&private_date)
            .map_err(|e| KeyManagerError::new(format!("加载 DER 私钥失败: {}", e)))
            .unwrap();
        let signature = algorithm.sign(&pkey, data).unwrap();
        println!("Signature: {:?}", signature);
    }

    #[test]
    fn test_verify() {
        let algorithm = RsaAlgorithm {
            _bits: 2048,
            padding: "pss".to_string(),
        };
        let private_key_str = "\n-----BEGIN PRIVATE KEY-----\nLS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ3dxSnZsOTNjYVhhc1cKQXZBM2hiMkRzTFBvc1RZblhXT1dzUHkySWRiY1dva01nTVR0TWZjbTY5Smc4QVZXTU5idjE2bEFvaDRYaFduQwpLSElFdEthMld0MVhsKy9QV3pYSm16RFI0ZmNCempFYTRKdWNKeElWR1RmV0U0YUY5SmpZZUVhV1FNUnMwT3poClN5Sk54cWtrd0tOMnprQ3R1VWowZkNSNmc1M3ZFeFFpajhtaGYzWktLVW0rSVh5eVFBSFZwM2w3YWVUUWxIV08KSHk0Nk9rTEFHTjVmZWlaTFNYT1k4ais4clpYcUptcjVoWS9rRmV1dUlCZDA4UEdQVW43YnRhNE4zaFlYZ1F4OQpBU3Nna3ZsVTVobVpKN1FSSTdNbVZOSWMxUzMrT3A5TXFXWjdtY0RrUXJIM1FjTjdPSms4STdJR0xUZ2lTTmZICnRTZTVZSnkxQWdNQkFBRUNnZ0VBRjN5REpZTE9BZUpjSVpRSWJjbEpGZDREUFRkNk5LZVUydTd5MmlBTG1jWXIKbkU3dVgzNmFGa0daK2F0UGVsTUo4Rjhpc0dZZFRCRS9xMEdIVHhyWll6c1hYRkxsM2hLSlJ5RnJ6eXVVbEZmZQpiVzFaSXR5SzZlVXRhRGUyVmM3Y0YwTitWdkdMYTlBbS9oam9HYUVFMGM4T3JIZmxYM05Yd0xGVWhEbEZZUWhXCmxualV0Z3R2aVZXa3F3MWppOUtWZjh5MTBaUm5TUHhqQ292K215R3hGUkhXYWFqNHU1Y0VuQkU4MnIzazkrQ1IKNHRXMXRBT0Y1KzNFeC9VZXY5SjlOcmpxWTYwSFBLMHF5bGZudDVGRyttS21YbDBwcFJuZWN4QWtWeVV3dDVQOApLTHNOU21RR3hvamo3RXMwRVBxU1NuVDVXTUR4Ri9XQ3VrUVdIUStTd1FLQmdRRG1PVlJCOGl3bjZDWWFydmJuCmJRbmprN3BRV2l0MTV0VXJrVC9mSUdQT295K2M0R3BMUFdpWjczUkY3TCtNcXNyRXdyc2JqZkZtYjJKbFVmc3oKUmd4a3JMdkczVnplUERwUXFPYUdRUmtNdlp6M3NVaHZKOHJSNUVOYmlVeXM4S1piZlM0RmlSQWp4Rzl4TUoyWgpIb0FCUWVmSHhSRjVEVUk3QUw1NUV4cVdNUUtCZ1FERWIvNGVGNEhxMkhHS1RDR0xvSVpnOFNhY3k3ek9lckg2CmU5UUZwTTJMY3VJcEoyZnQ5WlpWUytNeWJrWURNNTU0TU40ZnlQVmRvQzNoNnpKc3FwdDd5RUZMNjcxejNLeTcKYm51Wno4bHFCNjR1cUNoZXE5WTc3bGZnNWlyZW83b09tL0RZU0JZNmFtOHlLd0VlR3RSSzJicit6TWR0SSs4Twp5SlhGY2ZSWnhRS0JnQ0hmNzVqZ2RFVE84TVJlV0RBSEtEeFhJVVB2Y0pPaGlsNGx1aHN2bmQvcXZQZTlRWWFlCm00U0M2ajNicnZlWXJjc3p4K292QVlVTUFKTmQ4N05BckZRbjRsMUpkdit3SnZoMVVhNFJhQWtxNFN6RTVoNk0KNFZmdTJVWmZ0bXQvNFVwMjZjMmd0RUkvQmhMR2ozblhOZ2g1VlF4YzM4eEsraUxLWWp4WVprSVJBb0dBSzlDMwpJOHNtaFZXRjdjMFJabTJGeTdXK1lSYm9wRDJsMlRNcGxhQ3U0RDNkeUVRcjRGMzVERW1EQWNxcS95ZlNYd2kzCll1dVdIeTROVGVrQ05FN1JvNGlGV0FQYkhDN0tzSHZ5UWRxaEdHOWlJTElOWHlDQkJwa2hMTjdxRFFNRUN5SXAKVkhTdjBKUFEvYVd0K0NNUDJ5bzVsWC9qczZwaU5pL3ppRGprd2VrQ2dZRUFwSVZjTGI2MmtaWWFFaHpHazBRQgpJejk0M3VxekR2YkQvdUxlemdHREFNN09UaEVFRlpkazBOQWwwbnNZV0RQaDJFVXJlSVJvcmx3RkFrVFBMMEw1Cmp3cnprS2RlSDcxemVBSldDWVpVSVhTRVk3Y1J3UEp4S3FKSG44NS9UUVBDdGhlelAwTGxPb0M4L2c2aWlaWmIKRkRNWEhyVjcvRXNRUXdUcjFadEYveWM9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K\n-----END PRIVATE KEY-----\n";
        let private_date = decode_from_string(private_key_str, "pem").unwrap();
        let public_key = algorithm.derive_public(&private_date).unwrap();
        let key_pair = KeyPair {
            cached_private: OnceCell::new(),
            cached_public: OnceCell::new(),
            private_bytes: private_date,
            public_bytes: public_key,
            algorithm: "rsa".to_string(),
        };
        let private_key = key_pair.private_key();
        let public_key = key_pair.public_key();
        let data = "17416643274gswQhRl1wTRrWLWJ/LUmwxnWmk=".as_bytes().to_vec();
        let signature = algorithm.sign(&private_key, data.clone()).unwrap();
        let is_valid = algorithm.verify(&public_key, data, signature).unwrap();
        println!("Is valid: {:?}", is_valid);
    }
}
